package com.dreamlin.lindownload;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;

import androidx.annotation.NonNull;

import com.dreamlin.lindownload.entity.LinTaskBean;
import com.dreamlin.lindownload.set.TaskQueue;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;

/**
 * <p> Title: LinDownload </p>
 * <p> Description: 目前只是实现了最基本的功能,需要优化的东西很多</p>
 *
 * @author: dreamlin
 * @date: 2020/5/5
 * @version: V1.0.0
 * Created by dreamlin on 2020/5/5.
 */
public class LinDownload {

    static final long KB = 1024;
    static final long MB = KB << 10;
    static final long GB = MB << 10;

    private static volatile LinDownload instance;
    //下载状态
    public static final int STATUS_NONE = 0x11;
    public static final int STATUS_DOWNLOAD = 0x12;
    public static final int STATUS_PAUSE = 0x13;
    public static final int STATUS_FINISH = 0x14;
    public static final int STATUS_CANCEL = 0x15;
    public static final int STATUS_FAILED = 0x15;
    public static final int STATUS_WAITING = 0x16;

    public static long DEFAULT_INTERVAL = 500L;
    public static int DEFAULT_AUTO_RETRY = 0;
    public static int DEFAULT_THREAD_NUM = 1;

    //最大同时下载任务数量
    static final int MAX_TASK_NUMBER = 6;
    //单任务最大线程数量
    static final int MAX_THREAD_NUMBER = 100;
    static int runTaskNumber = 0;
    static int status = STATUS_NONE;
    static HashMap<String, LinDownloadTask> taskMap = new HashMap<>();
    static TaskQueue waitQueue = new TaskQueue();
    private static WeakReference<LinDownloadListener> weakListener;

    public static void init(Context context) {
        Realm.init(context);
        RealmConfiguration builder = new RealmConfiguration.Builder().deleteRealmIfMigrationNeeded()
                .build();
        Realm.setDefaultConfiguration(builder);
    }

    public static void setListener(LinDownloadListener listener) {
        weakListener = new WeakReference<>(listener);
    }

    public static LinTaskImp with(String url) {
        if (taskMap.containsKey(url)) {
            return taskMap.get(url);
        } else if (waitQueue.contains(url)) {
            return waitQueue.peek();
        }
        return new LinDownloadTaskImp(url, weakListener == null ? null : weakListener.get());
    }

    public static int getStatus(String url) {
        if (taskMap.containsKey(url)) {
            return taskMap.get(url).getStatus();
        } else if (waitQueue.contains(url)) {
            return STATUS_WAITING;
        }
        return STATUS_NONE;
    }

    public static boolean isExists(String url) {
        return taskMap.containsKey(url) || waitQueue.contains(url);
    }

    public static boolean isDownloading(String url) {
        return taskMap.containsKey(url) && taskMap.get(url).getStatus() == STATUS_DOWNLOAD;
    }

    public static boolean isPause(String url) {
        return taskMap.containsKey(url) && taskMap.get(url).getStatus() == STATUS_PAUSE;
    }

    public static boolean isWait(String url) {
        return waitQueue.contains(url);
    }

    public static boolean start(String url) {
        if (taskMap.containsKey(url)) {
            taskMap.get(url).start();
            return true;
        } else if (waitQueue.contains(url)) {
            waitQueue.get(url).start();
            return true;
        }
        return false;
    }

    /**
     * @param url
     * @return false:不存在的任务
     */
    public static boolean pause(String url) {
        if (taskMap.containsKey(url)) {
            taskMap.get(url).pause();
            return true;
        } else if (waitQueue.contains(url)) {
            waitQueue.get(url).pause();
            return true;
        }
        return false;
    }

    public static boolean cancel(String url) {
        if (taskMap.containsKey(url)) {
            taskMap.get(url).cancel();
            return true;
        } else if (waitQueue.contains(url)) {
            waitQueue.get(url).cancel();
            return true;
        }
        return false;
    }

 /*   public static LinDownload getInstance() {
        if (instance == null) {
            synchronized (LinDownload.class) {
                if (instance == null) {
                    instance = new LinDownload();
                }
            }
        }
        return instance;
    }*/

    static void increase() {
        runTaskNumber++;
    }

    static void decrease() {
        runTaskNumber--;
        if (runTaskNumber < MAX_TASK_NUMBER) {
            if (waitQueue.size() > 0) {
                LinDownloadTaskImp poll = waitQueue.poll();
                poll.start();
            }
        }
    }

    public static void startAll() {
        if (taskMap.size() > 0) {
            Iterator<LinDownloadTask> iterator = taskMap.values().iterator();
            while (iterator.hasNext()) {
                LinDownloadTask next = iterator.next();
                if (next.getStatus() == STATUS_DOWNLOAD || next.getStatus() == STATUS_FINISH) {
                    return;
                }
                if (runTaskNumber < MAX_TASK_NUMBER) {
                    next.start();
                } else {
                    //添加到排队队列
                    waitQueue.add(new LinDownloadTaskImp(next.getLinTaskBean(), next.getListener()));
                    iterator.remove();
                }
            }
        }

    }

    public static void stopAll() {
        if (taskMap.size() > 0) {
            Iterator<LinDownloadTask> iterator = taskMap.values().iterator();
            while (iterator.hasNext()) {
                LinDownloadTask next = iterator.next();
                if (next.getStatus() == STATUS_DOWNLOAD)
                    next.pause();
            }
        }
        status = STATUS_PAUSE;
    }

    public static void cancelAll() {
        if (taskMap.size() > 0) {
            Iterator<LinDownloadTask> iterator = taskMap.values().iterator();
            while (iterator.hasNext()) {
                LinDownloadTask next = iterator.next();
                if (next.getStatus() == STATUS_DOWNLOAD ||
                        next.getStatus() == STATUS_PAUSE ||
                        next.getStatus() == STATUS_FAILED) {
                    next.cancel();
                    iterator.remove();
                }
            }
        }
        status = STATUS_PAUSE;
    }

    private LinDownload() {
        throw new ArithmeticException("can't be init");
    }

    /**
     * @param taskListener 异步加载任务列表监听
     * @param listener     默认任务监听
     */
    public static void loadTaskList(@NonNull final TaskListener taskListener, LinDownloadListener listener) {
        if (taskMap.size() > 0 || waitQueue.size() > 0)
            return;
        setListener(listener);
        @SuppressLint("StaticFieldLeak")
        AsyncTask<Object, Object, List<LinTaskBean>> asyncTask = new AsyncTask<Object, Object, List<LinTaskBean>>() {

            @Override
            protected List<LinTaskBean> doInBackground(Object... objects) {
                Realm realm = Realm.getDefaultInstance();
                List<LinTaskBean> linTaskBeans = new ArrayList<>();
                try {
                    RealmResults<LinTaskBean> all = realm.where(LinTaskBean.class)
                            .findAll();
                    if (all != null && all.size() > 0) {
                        linTaskBeans.addAll(realm.copyFromRealm(all));
                        for (LinTaskBean bean :
                                linTaskBeans) {
                            if (bean.getState() == STATUS_WAITING) {
                                LinDownloadTaskImp linDownloadTaskImp = new LinDownloadTaskImp(bean, weakListener.get());
                                waitQueue.add(linDownloadTaskImp);
                            } else if (bean.getState() == STATUS_DOWNLOAD ||
                                    bean.getState() == STATUS_PAUSE) {
                                LinDownloadTask linDownloadTask = new LinDownloadTask(bean, weakListener.get());
                                taskMap.put(bean.getUrl(), linDownloadTask);
                                if (bean.getState() == STATUS_DOWNLOAD) {
                                    linDownloadTask.start();
                                }
                            }
                        }
                    }
                } finally {
                    realm.close();
                    return linTaskBeans;
                }
            }

            @Override
            protected void onPostExecute(List<LinTaskBean> linTaskBeans) {
                super.onPostExecute(linTaskBeans);
                taskListener.onTaskReady(linTaskBeans);
            }
        };
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 1);
    }

    @SuppressLint("DefaultLocale")
    static String calculateSpeed(long lastFinished, long curFinished, long callInterval) {
        double interval = (float) callInterval / 1000f;
        double diff = (curFinished - lastFinished) / interval;
        if (diff < KB) {
            return String.format("%.0f b/s", diff);
        } else if (diff >= KB && diff < MB) {
            return String.format("%.0f kb/s", diff / KB);
        } else if (diff >= MB && diff < GB) {
            return String.format("%.2f Mb/s", diff / MB);
        } else {
            return String.format("%.2f GB/s", diff / GB);
        }
    }

}
